#include "loradevice.h"
#include <iostream>

namespace cores
{
    namespace devices
    {
        LoraDeviceManager *LoraDeviceManager::globalInstance{nullptr};

        LoraDeviceManager::LoraDeviceManager()
        {
            if (LoraDeviceManager::globalInstance == nullptr)
            {
                LoraDeviceManager::globalInstance = this;
            }
        }

        LoraDeviceManager::~LoraDeviceManager()
        {
            if (LoraDeviceManager::globalInstance == this)
            {
                LoraDeviceManager::globalInstance = nullptr;
            }
        }

        int LoraDeviceManager::Count()
        {
            assert(LoraDeviceManager::globalInstance);
            return LoraDeviceManager::globalInstance->count();
        }

        OilTransReq *LoraDeviceManager::Get(const uint16_t &loraId, const uint8_t &nozzlecode)
        {
            assert(LoraDeviceManager::globalInstance);
            return LoraDeviceManager::globalInstance->get(loraId, nozzlecode);
        }

        OilTransReq *LoraDeviceManager::Get(const int &i)
        {
            assert(LoraDeviceManager::globalInstance);
            return LoraDeviceManager::globalInstance->get(i);
        }

        void LoraDeviceManager::Add(const OilTransReq &device)
        {
            assert(LoraDeviceManager::globalInstance);

            auto tmp = shared_ptr<OilTransReq>(new OilTransReq);
            tmp->lora_id = device.lora_id;
            tmp->nozzle_code = device.nozzle_code;
            tmp->category = device.category;
            tmp->screen_type = device.screen_type;
            tmp->rate = device.rate;
            tmp->current_req_num = device.current_req_num;
            tmp->current_tax_num = device.current_tax_num;
            tmp->has_data = device.has_data;
            tmp->is_answer = device.is_answer;
            tmp->no_answer_count = device.no_answer_count;
            tmp->error_count = device.error_count;
            tmp->is_config_error = device.is_config_error;

            LoraDeviceManager::globalInstance->add(tmp);
        }

        void LoraDeviceManager::Add(const OilTransReq *device)
        {
            assert(LoraDeviceManager::globalInstance);

            auto tmp = shared_ptr<OilTransReq>(new OilTransReq);
            tmp->lora_id = device->lora_id;
            tmp->nozzle_code = device->nozzle_code;
            tmp->category = device->category;
            tmp->screen_type = device->screen_type;
            tmp->rate = device->rate;
            tmp->current_req_num = device->current_req_num;
            tmp->current_tax_num = device->current_tax_num;
            tmp->has_data = device->has_data;
            tmp->is_answer = device->is_answer;
            tmp->no_answer_count = device->no_answer_count;
            tmp->error_count = device->error_count;
            tmp->is_config_error = device->is_config_error;

            LoraDeviceManager::globalInstance->add(tmp);
        }

        void LoraDeviceManager::Clear()
        {
            assert(LoraDeviceManager::globalInstance);
            LoraDeviceManager::globalInstance->clear();
        }

        int LoraDeviceManager::count()
        {
            return _devices.size();
        }

        OilTransReq *LoraDeviceManager::get(const uint16_t &loraId, const uint8_t &nozzlecode)
        {
            if (_devices.count(loraId) == 0)
                return nullptr;

            return _devices[loraId << 16 + nozzlecode].get();
        }

        OilTransReq *LoraDeviceManager::get(const int &i)
        {
            auto iter = _devices.begin();
            auto count = 0;
            while (count < i && iter != _devices.end())
            {
                iter++;
                count++;
            }

            if (iter == _devices.end())
                return nullptr;

            return iter->second.get();
        }

        void LoraDeviceManager::add(shared_ptr<OilTransReq> device)
        {
            if (device.get() == nullptr)
                return;

            _devices[device->lora_id << 16 + device->nozzle_code] = device;
            if (_devicesByLoraId.count(device->lora_id) > 0)
            {
                auto &_ds = _devicesByLoraId[device->lora_id];
                _ds.push_back(device.get());
            }
            else
            {
                _devicesByLoraId[device->lora_id] = {device.get()};
            }
        }

        void LoraDeviceManager::clear()
        {
            _devices.clear();
        }

        void LoraDeviceManager::Print()
        {
            assert(LoraDeviceManager::globalInstance);
            LoraDeviceManager::globalInstance->print();
        }

        void LoraDeviceManager::print()
        {
            for (auto &device : _devices)
            {
                std::cout << "----------------------" << device.second->lora_id << "---------------------" << std::endl;
                std::cout << "lora id: " << device.second->lora_id << std::endl;
                std::cout << "nozzle code:" << int(device.second->nozzle_code) << std::endl;
                std::cout << "category:" << int(device.second->category) << std::endl;
                std::cout << "screen_type:" << int(device.second->screen_type) << std::endl;
                std::cout << "rate:" << int(device.second->rate) << std::endl;
                std::cout << "current_req_num:" << device.second->current_req_num << std::endl;
                std::cout << "has_data:" << (device.second->has_data ? "true" : "false") << std::endl;
                std::cout << "is_answer:" << (device.second->is_answer ? "true" : "false") << std::endl;
                std::cout << "no_answer_count:" << device.second->no_answer_count << std::endl
                          << std::endl;
            }

            for (auto &devices : _devicesByLoraId)
            {
                std::cout << "-----------------------" << devices.first << "-----------------------" << std::endl;
                for (auto &device : devices.second)
                {
                    std::cout << "----------------------" << int(device->nozzle_code) << "----------------------" << std::endl;
                    std::cout << "category:" << int(device->category) << std::endl;
                    std::cout << "screen_type:" << int(device->screen_type) << std::endl;
                    std::cout << "rate:" << int(device->rate) << std::endl;
                    std::cout << "current_req_num:" << device->current_req_num << std::endl;
                    std::cout << "has_data:" << (device->has_data ? "true" : "false") << std::endl;
                    std::cout << "is_answer:" << (device->is_answer ? "true" : "false") << std::endl;
                    std::cout << "no_answer_count:" << device->no_answer_count << std::endl;
                }
            }
        }

        vector<uint16_t> LoraDeviceManager::GetLoraIDVector()
        {
            assert(LoraDeviceManager::globalInstance);
            return LoraDeviceManager::globalInstance->getLoraIds();
        }

        vector<uint16_t> LoraDeviceManager::getLoraIds()
        {
            auto result = vector<uint16_t>();
            for (auto &device : _devices)
            {
                auto loraId = device.second->lora_id;
                auto iter = result.begin();
                for (/* 空 */; iter != result.end(); iter++)
                {
                    if (*iter == loraId)
                        break;
                }

                if (iter == result.end())
                    result.push_back(loraId);
            }
            return result;
        }

        const vector<OilTransReq*> LoraDeviceManager::GetOilTrans(const uint16_t& loraId)
        {
            assert(LoraDeviceManager::globalInstance);
            return LoraDeviceManager::globalInstance->getOilTrans(loraId);
        } 

        const vector<OilTransReq*> LoraDeviceManager::getOilTrans(const uint16_t& loraId)
        {
            if (_devicesByLoraId.count(loraId) == 0)
                return vector<OilTransReq*>();
            else
                return _devicesByLoraId[loraId];
        }
    }
}